package com.zhangfb95.crosschain.infra.util.tls.client;

import com.zhangfb95.crosschain.infra.enums.SslTypeEnum;
import io.netty.handler.ssl.ClientAuth;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;

import javax.net.ssl.SSLException;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;

/**
 * @author zhangfubing
 * @since 2023/12/28
 */
public class ReactorNettyWebClientBuilder {

    public static WebClient build(WebClientSslProperties sslProperties) {
        SslContext sslContext;
        try {
            if (SslTypeEnum.NONE.is(sslProperties.getSslType())) {
                sslContext = SslContextBuilder.forClient()
                        .trustManager(InsecureTrustManagerFactory.INSTANCE)
                        .build();
            } else if (SslTypeEnum.in(sslProperties.getSslType(), SslTypeEnum.RSA, SslTypeEnum.ECDSA)) {
                ByteArrayInputStream caCertInputStream =
                        new ByteArrayInputStream(sslProperties.getCaCert().getBytes(StandardCharsets.UTF_8));
                ByteArrayInputStream sslCertInputStream =
                        new ByteArrayInputStream(sslProperties.getSslCert().getBytes(StandardCharsets.UTF_8));
                ByteArrayInputStream sslKeyInputStream =
                        new ByteArrayInputStream(sslProperties.getSslKey().getBytes(StandardCharsets.UTF_8));

                sslContext = SslContextBuilder.forClient()
                        .trustManager(caCertInputStream)
                        .keyManager(sslCertInputStream, sslKeyInputStream)
                        .sslProvider(SslProvider.JDK)
                        .clientAuth(ClientAuth.REQUIRE)
                        .build();
            } else {
                throw new UnsupportedOperationException();
            }
        } catch (SSLException e) {
            throw new RuntimeException(e);
        }

        HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(sslContext));
        return WebClient.builder()
                .baseUrl(sslProperties.getServerUrl())
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .build();
    }
}
